#include "const/oPreDefine.h"
#include "model/oModelCache.h"
#include "model/oModelDef.h"
#include "const/oXml.h"
#include "model/oClipCache.h"
#include "misc/oContent.h"
#define oCase case oModelXml

const uint32 oModelCache::MAX_LOOKS = 128;

oAnimationDef* oModelCache::getAnimationForFrame()
{
	if (!_pCurrentAction)
	{
		_pCurrentAction = new oAnimationDef();
	}
	return (oAnimationDef*)_pCurrentAction;
}

void oModelCache::startElement( void *ctx, const char *name, const char **atts )
{
	switch (name[0])
	{
	oCase::Dorothy:
		{
			for (int i = 0;atts[i] != nullptr;i++)
			{
				switch (atts[i][0])
				{
				oCase::File:
					_item->_clip = atts[++i];
					_pCurrentClip = oSharedClipCache.load(_item->_clip.c_str());
					_pCurrentTex = oSharedContent.loadTexture(_pCurrentClip->textureFile.c_str());
					_item->setTexture(_pCurrentTex);
					break;
				oCase::FaceRight:
					_item->_isFaceRight = (atoi(atts[++i]) == 1);
					break;
				}
			}
		}
		break;
	oCase::Sprite:
		{
			int clip = -1;
			float x = 0.0f, y = 0.0f;
			float rot = 0.0f;
			float archorX = 0.5f, archorY = 0.5f;
			float scaleX = 1.0f, scaleY = 1.0f;
			GLubyte opacity = 255;
			if (atts)
			{
				for (int i = 0;atts[i] != nullptr;i++)
				{
					switch (atts[i][0])
					{
					oCase::Position:
						oGetPosFromStr(atts[++i], x, y);
						break;
					oCase::Rotation:
						rot = (float)atof(atts[++i]);
						break;
					oCase::Key:
						oGetPosFromStr(atts[++i], archorX, archorY);
						break;
					oCase::Clip:
						clip = atoi(atts[++i]);
						break;
					oCase::Scale:
						oGetPosFromStr(atts[++i], scaleX, scaleY);
						break;
					oCase::Opacity:
						opacity = (GLubyte)atoi(atts[++i]);
						break;
					}
				}
			}
			oSpriteDef* spriteDef = new oSpriteDef(
				_pCurrentTex,
				x, y,
				scaleX, scaleY,
				rot,
				archorX, archorY,
				clip == -1 ? CCRectZero : _pCurrentClip->rects[clip],
				clip,
				opacity);
			_nodeStack.push(spriteDef);
		}
		break;
	oCase::Frame:
		{
			float duration = 0.0f;
			float x = 0.0f, y = 0.0f;
			float scaleX = 1.0f, scaleY = 1.0f;
			float rot = 0.0f;
			GLubyte opacity = 255;
			int easePos = 0, easeScale = 0, easeRotate = 0, easeOpacity = 0;
			if (atts)
			{
				for (int i = 0;atts[i] != nullptr;i++)
				{
					switch (atts[i][0])
					{
					oCase::Duration:
						duration = (float)atof(atts[++i]);
						break;
					oCase::Position:
						oGetPosFromStr(atts[++i], x, y);
						break;
					oCase::Rotation:
						rot = (float)atof(atts[++i]);
						break;
					oCase::Scale:
						oGetPosFromStr(atts[++i], scaleX, scaleY);
						break;
					oCase::Opacity:
						opacity = (GLubyte)atoi(atts[++i]);
						break;
					oCase::EasePos:
						easePos = atoi(atts[++i]);
						break;
					oCase::EaseScale:
						easeScale = atoi(atts[++i]);
						break;
					oCase::EaseRotate:
						easeRotate = atoi(atts[++i]);
						break;
					oCase::EaseOpacity:
						easeOpacity = atoi(atts[++i]);
						break;
					}
				}
			}
			oKeyFrameDef* frameDef = new oKeyFrameDef(duration, x, y, rot, scaleX, scaleY, opacity);
			frameDef->easePos = easePos;
			frameDef->easeScale = easeScale;
			frameDef->easeRotate = easeRotate;
			frameDef->easeOpacity = easeOpacity;
			oAnimationDef* actionDef = oModelCache::getAnimationForFrame();
			actionDef->add(frameDef);
		}
		break;
	oCase::Animate:
		{
			oFrameAnimationDef* animationFrameDef = nullptr;
			float begin = 0.0f;
			float end = 0.0f;
			for (int i = 0;atts[i] != nullptr;i++)
			{
				switch (atts[i][0])
				{
				oCase::File:
					animationFrameDef = new oFrameAnimationDef(atts[++i], begin, end);
					break;
				oCase::Begin:
					begin = (float)atof(atts[++i]);
					break;
				oCase::End:
					end = (float)atof(atts[++i]);
					break;
				}
			}
			oSpriteDef* nodeDef = _nodeStack.top();
			nodeDef->addAction(animationFrameDef);
		}
		break;
	oCase::Look:
		{
			for (int i = 0;atts[i] != nullptr;i++)
			{
				switch (atts[i][0])
				{
					oCase::Index:
					{
						oSpriteDef* nodeDef = _nodeStack.top();
						char lookStr[MAX_LOOKS*2];
						strcpy(lookStr, atts[++i]);
						char* token = strtok(lookStr, ",");
						while(token != nullptr)
						{
							int look = atoi(token);
							nodeDef->addLook(look);
							token = strtok(nullptr, ",");
						}
					}
					break;
				}
			}
		}
		break;
	oCase::ActionName:
		{
			int index;
			const char* name;
			for (int i = 0;atts[i] != nullptr;i++)
			{
				switch (atts[i][0])
				{
					oCase::Index:
						index = atoi(atts[++i]);
						break;
					oCase::Name:
						name = atts[++i];
						break;
				}
			}
			_item->_actionIndex[name] = index;
		}
		break;
	oCase::LookName:
		{
			int index;
			const char* name;
			for (int i = 0;atts[i] != nullptr;i++)
			{
				switch (atts[i][0])
				{
					oCase::Index:
						index = atoi(atts[++i]);
						break;
					oCase::Name:
						name = atts[++i];
						break;
				}
			}
			_item->_lookIndex[name] = index;
		}
		break;
	}
}

void oModelCache::endElement( void *ctx, const char *name )
{
	switch (name[0])
	{
	oCase::Sprite:
		{
			oSpriteDef* nodeDef = _nodeStack.top();
			_nodeStack.pop();
			if (_nodeStack.empty())
			{
				_item->setRoot(nodeDef);
			}
			else
			{
				oSpriteDef* parentDef = _nodeStack.top();
				parentDef->addChild(nodeDef);
			}
		}
		break;
	oCase::Action:
		{
			oSpriteDef* nodeDef = _nodeStack.top();
			nodeDef->addAction(_pCurrentAction);
			_pCurrentAction = nullptr;
		}
		break;
	}
}

void oModelCache::textHandler( void *ctx, const char *s, int len )
{ }

void oModelCache::beforeParse( const char* filename )
{		
	for (;!_nodeStack.empty();_nodeStack.pop());
	_pCurrentClip = nullptr;
	_pCurrentAction = nullptr;
	_item = new oModelDef();
}

void oModelCache::afterParse( const char* filename )
{ }
